package converter

import (
	"fmt"
	"reflect"
	"strings"
	"sync"
)

var fieldCache sync.Map

type fieldInfo struct {
	Index int
	Type  reflect.Type
}

func getFieldName(field reflect.StructField) string {
	if tag := field.Tag.Get("json"); tag != "" {
		return strings.Split(tag, ",")[0]
	}
	return field.Name
}

func getCachedFields(t reflect.Type) map[string]fieldInfo {
	if v, ok := fieldCache.Load(t); ok {
		return v.(map[string]fieldInfo)
	}

	fields := make(map[string]fieldInfo)
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		fields[getFieldName(f)] = fieldInfo{Index: i, Type: f.Type}
	}

	fieldCache.Store(t, fields)
	return fields
}

func canAssign(modelField, voField reflect.Value) bool {
	if modelField.Type().AssignableTo(voField.Type()) {
		return true
	}

	if modelField.Type().ConvertibleTo(voField.Type()) {
		return true
	}

	if modelField.Kind() == reflect.Ptr {
		return modelField.Elem().Type().AssignableTo(voField.Type())
	}

	if voField.Kind() == reflect.Ptr {
		return modelField.Type().AssignableTo(voField.Type().Elem())
	}

	return false
}

func ToVO[T any, V any](model T, vo *V) (*V, error) {
	modelValue := reflect.ValueOf(model)
	if modelValue.Kind() == reflect.Ptr && modelValue.IsNil() {
		return nil, nil
	}

	// 处理指针类型，获取实际的结构体类型
	if modelValue.Kind() == reflect.Ptr {
		modelValue = modelValue.Elem()
	}

	voValue := reflect.ValueOf(vo)
	if voValue.Kind() != reflect.Ptr || voValue.IsNil() {
		return nil, fmt.Errorf("vo must be a non-nil pointer")
	}
	voValue = voValue.Elem()

	modelFields := getCachedFields(modelValue.Type()) // 现在传入的是结构体类型
	voFields := getCachedFields(voValue.Type())

	for name, voFieldInfo := range voFields {
		if modelFieldInfo, ok := modelFields[name]; ok {
			modelField := modelValue.Field(modelFieldInfo.Index)
			voField := voValue.Field(voFieldInfo.Index)

			if canAssign(modelField, voField) {
				if modelField.Type().ConvertibleTo(voField.Type()) {
					voField.Set(modelField.Convert(voField.Type()))
				} else {
					voField.Set(modelField)
				}
			}
		}
	}

	return vo, nil
}

// 修改后的 ToVOList 函数
func ToVOList[T any, V any](models []T, voType V) ([]*V, error) {
	if len(models) == 0 {
		return nil, nil
	}

	voTypeValue := reflect.TypeOf(voType)
	result := make([]*V, 0, len(models))

	for _, model := range models {
		newVO := reflect.New(voTypeValue).Interface().(*V)

		// 使用 reflect.ValueOf 获取模型值
		modelValue := reflect.ValueOf(model)
		if modelValue.Kind() == reflect.Ptr && modelValue.IsNil() {
			result = append(result, nil)
			continue
		}

		if _, err := ToVO(model, newVO); err != nil {
			return nil, err
		}
		result = append(result, newVO)
	}

	return result, nil
}

// 填充VO中的Name值 通过ID
type FillOptions struct {
	EntityIDField   string // 实体中的ID字段名（默认 "ID"）
	EntityNameField string // 实体中的名称字段名（默认 "Name"）
}

func FillNameField[V any, E any](
	vos []*V,
	entities []E,
	idFieldName string,
	nameFieldName string,
	opts ...FillOptions,
) error {
	// 默认配置
	opt := FillOptions{
		EntityIDField:   "ID",
		EntityNameField: "Name",
	}
	if len(opts) > 0 {
		opt = opts[0]
	}

	// 构建名称映射
	nameMap := make(map[any]string)
	for _, e := range entities {
		v := reflect.ValueOf(e)
		if v.Kind() == reflect.Ptr {
			v = v.Elem()
		}

		idField := v.FieldByName(opt.EntityIDField)
		if !idField.IsValid() {
			return fmt.Errorf("实体缺少ID字段: %s", opt.EntityIDField)
		}

		nameField := v.FieldByName(opt.EntityNameField)
		if !nameField.IsValid() {
			return fmt.Errorf("实体缺少名称字段: %s", opt.EntityNameField)
		}

		nameMap[idField.Interface()] = nameField.String()
	}

	// 填充VO
	for _, vo := range vos {
		if vo == nil {
			continue
		}

		voValue := reflect.ValueOf(vo).Elem()
		idField := voValue.FieldByName(idFieldName)
		if !idField.IsValid() {
			return fmt.Errorf("VO缺少ID字段: %s", idFieldName)
		}

		nameField := voValue.FieldByName(nameFieldName)
		if !nameField.IsValid() {
			return fmt.Errorf("VO缺少名称字段: %s", nameFieldName)
		}

		if name, ok := nameMap[idField.Interface()]; ok {
			nameField.SetString(name)
		}
	}

	return nil
}
